/**
 * 
 */
package com.zznode.client.wlanpolling.test;

import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.PointStyle;
import org.achartengine.model.TimeSeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.zznode.client.wlanpolling.R;
import com.zznode.client.wlanpolling.WLANPollingApplication;
import com.zznode.client.wlanpolling.WLanContext;
import com.zznode.client.wlanpolling.model.TestResultConstants;
import com.zznode.client.wlanpolling.model.WLANPollManager;
import com.zznode.client.wlanpolling.utils.NetworkUtils;
import com.zznode.client.wlanpolling.utils.PingUtils;

/**
 * @author Bean
 * 
 */
public class ReassociateTestActivity extends Activity {

	private static final int UPDATE_ASSOCIATE_TESTBEGIN = 0;
	private static final int UPDATE_ASSOCIATE_STATUS = 1;
	private static final int UPDATE_ASSOCIATE_RESULT = 2;
	private static final int UPDATE_ASSOCIATE_TESTOVER = 3;
	private static final int UPDATE_ASSOCIATE_CHART = 4;
	
	private WLANPollingApplication application;
	
	private WifiBroadcastReceiver wifiReceiver;
	private WifiManager wifiManager;
	private XYMultipleSeriesDataset dataset;
	private GraphicalView chartView;
	private XYMultipleSeriesRenderer renderer;

	private TextView txtCurrTestTimes;
	private TextView txtCurrDelay;
	private TextView txtAverageDelay;

	private TextView txtResultTimes;
	private TextView txtResultSuccessTimes;
	private TextView txtResultSuccessPercent;
	private TextView txtResultAverateDelay;

	private Button btnBeginTest;
	
	private UpdateUIHandler updateUIHandler;

	private EnumTestStatus testStatus;

	private int testTimes = 0;
	private int testTotalTimes = 0;
	private long beginReassociateTime;
	private int totalDelay = 0;

	// 测试结果
	private long currentDelay = 0;
	private long maxDelay = 10;
	private long averageDelay = 0;
	private int associateSuccess = 0;
	private int associateFailed = 0;
	
	private Timer reassociateTimer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.reassociatetest);
		application = (WLANPollingApplication)getApplication();
		
		testStatus = EnumTestStatus.STOP;
		bindView();
		bindEvent();
		initData();
		
		updateUIHandler = new UpdateUIHandler(Looper.myLooper());
	}

	private void resetTestStatus() {
		beginReassociateTime = 0;
		testTimes = 0;
		currentDelay = 0;
		averageDelay = 0;
		associateSuccess = 0;
		associateFailed = 0;
		totalDelay = 0;
		
		WLanContext wlanContext = application.getContext();
		testTotalTimes = wlanContext.getSystemSetting().getRelateTestTimes();
		
		if(dataset.getSeriesCount() > 0) {
			dataset.getSeriesAt(0).clear();
		}
		
		renderer.setYAxisMax(10);
		
		LinearLayout layout = (LinearLayout) findViewById(R.id.testResultLayout);
		layout.setVisibility(View.GONE);
	}

	private void bindView() {

		txtCurrTestTimes = (TextView) findViewById(R.id.txtCurrTestTimes);
		txtCurrDelay = (TextView) findViewById(R.id.txtCurrDelay);
		txtAverageDelay = (TextView) findViewById(R.id.txtAverageDelay);

		txtResultTimes = (TextView) findViewById(R.id.txtResultTimes);
		txtResultSuccessTimes = (TextView) findViewById(R.id.txtResultSuccessTimes);
		txtResultSuccessPercent = (TextView) findViewById(R.id.txtResultSuccessPercent);
		txtResultAverateDelay = (TextView) findViewById(R.id.txtResultAverateDelay);

		LinearLayout layout = (LinearLayout) findViewById(R.id.reassociatePlaceHolder);
		dataset = new XYMultipleSeriesDataset();

		TimeSeries series = new TimeSeries("Associate Test");

		dataset.addSeries(series);

		XYSeriesRenderer r = new XYSeriesRenderer();
		r.setColor(Color.GREEN);
		r.setPointStyle(PointStyle.POINT);

		renderer = new XYMultipleSeriesRenderer();

		renderer.addSeriesRenderer(r);
		renderer.setShowGridX(true);
		renderer.setXAxisMax(100);
		renderer.setXAxisMin(0);
		renderer.setShowAxes(true);
		renderer.setYAxisMax(10);
		renderer.setYAxisMin(0);
		renderer.setPanEnabled(true, false);
		renderer.setZoomEnabled(false);
		renderer.setShowLabels(true);
		renderer.setShowLegend(false);
		renderer.setXTitle("times");
		renderer.setYTitle("delay (s)");
		renderer.setFitLegend(true);
		renderer.setGridColor(Color.DKGRAY);
		renderer.setMarginsColor(Color.argb(0, 0xff, 0, 0));
		renderer.setBackgroundColor(Color.TRANSPARENT); // 设置背景色透明
		renderer.setApplyBackgroundColor(true); // 使背景色生效

		chartView = ChartFactory.getTimeChartView(this, dataset, renderer, "");

		layout.addView(chartView, new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.FILL_PARENT));
	}
	
	private void initData() {
		txtCurrTestTimes.setText("0/" + application.getContext().getSystemSetting().getRelateTestTimes());
		txtCurrDelay.setText("0ms");
		txtAverageDelay.setText("0ms");
	}
	

	private void bindEvent() {
		btnBeginTest = (Button) findViewById(R.id.btnBeginTest);

		btnBeginTest.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				
				/*
				if (wifiReceiver != null) {
					Toast.makeText(ReassociateTestActivity.this, "正在进行测试...",
							Toast.LENGTH_LONG).show();
					return;
				}
				*/
				if(testStatus == EnumTestStatus.STOP) {
					resetTestStatus();
	
					wifiReceiver = new WifiBroadcastReceiver();
					registerReceiver(wifiReceiver, new IntentFilter(
							ConnectivityManager.CONNECTIVITY_ACTION));
					wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
					beginReassociateTime = System.currentTimeMillis();
					wifiManager.reassociate();
					testStatus = EnumTestStatus.TESTING;
					testTimes = 1;
					btnBeginTest.setText("停止测试");
				} else if (testStatus == EnumTestStatus.TESTING) {
					try {
						if(wifiReceiver !=null)
							unregisterReceiver(wifiReceiver);
						testStatus = EnumTestStatus.STOP;
						btnBeginTest.setText("开始测试");
					} catch (Exception e) {
						// TODO: handle exception
					}
					
				}
			}

		});

		Button btnSave = (Button) findViewById(R.id.btnSave);

		btnSave.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO
				if(testStatus == EnumTestStatus.TESTING) {
					Toast.makeText(ReassociateTestActivity.this, "正在进行测试...",
							Toast.LENGTH_LONG).show();
					return;
				}
				
				saveAction();
			}
		});
	}
	
	public void saveAction() {
		String apMac = PingUtils.clearMacAdress(application.getContext().getCurrentWifi().getBSSID());

		Map<String, Object> values = new HashMap<String, Object>();

		values.put(TestResultConstants.RELTESTDELAY, averageDelay);
		values.put(TestResultConstants.RELTESTCOUNT, testTimes);
		
		WLANPollManager.getWLANPollManager().updateTestResult(application.getApplicationContext(), 
				apMac,
				values);
		values.put(TestResultConstants.SSID, application.getContext().getCurrentWifi().getSSID());
		
		Toast.makeText(this, "成功保存", Toast.LENGTH_SHORT).show();
	}
	

	@Override
	public void onBackPressed() {
		// TODO Auto-generated method stub
		if(testStatus == EnumTestStatus.TESTING) {
			Toast.makeText(ReassociateTestActivity.this, "正在进行测试...",
					Toast.LENGTH_LONG).show();
			return;
		}
		super.onBackPressed();
	}
	
	private void updateTestStatus(boolean success) {
		currentDelay = (System.currentTimeMillis() - beginReassociateTime);
		totalDelay += currentDelay;
		averageDelay = totalDelay / testTimes;

		DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
		WifiInfo wifiInfo = wifiManager.getConnectionInfo();
		String str = "";
		if(success) {
			str = "第" + testTimes + "次关联'"
				+ wifiInfo.getSSID() + "'成功, 关联时长:"
				+ currentDelay + "ms, IP地址"
				+ NetworkUtils.intToIp(dhcpInfo.ipAddress);
			associateSuccess++;
		} else {
			str = "第" + testTimes + "次关联'"
			+ wifiInfo.getSSID() + "'失败, 关联时长:"
			+ currentDelay + "ms";
			associateFailed++;
		}
		
		Message msg = new Message();
		msg.what = UPDATE_ASSOCIATE_STATUS;
		msg.obj = str;
		updateUIHandler.sendMessage(msg);

		ReassociateInfo reassociateInfo = new ReassociateInfo(
				currentDelay, averageDelay, associateSuccess,
				associateFailed);
		reassociateInfo.setTestTimes(testTimes);
		msg = new Message();
		msg.what = UPDATE_ASSOCIATE_CHART;
		msg.obj = reassociateInfo;
		updateUIHandler.sendMessage(msg);
		
		if (testTimes >= testTotalTimes) {
			testStatus = EnumTestStatus.STOP;
			// 测试结束
			str = "关联测试结束";
			msg = new Message();
			msg.what = UPDATE_ASSOCIATE_STATUS;
			msg.obj = str;
			updateUIHandler.sendMessage(msg);

			msg = new Message();
			msg.what = UPDATE_ASSOCIATE_RESULT;
			msg.obj = str;
			updateUIHandler.sendMessage(msg);
		}
	}
	
	private void startReassociate() {
		testTimes++;
		String str = "开始第" + testTimes + "次关联测试";
		Message msg = new Message();
		msg.what = UPDATE_ASSOCIATE_STATUS;
		msg.obj = str;
		updateUIHandler.sendMessage(msg);
		
		//设置超时Timer
		if(reassociateTimer != null) {
			reassociateTimer.cancel();
			reassociateTimer = null;
		}
		
		reassociateTimer = new Timer();
		reassociateTimer.schedule(new TimeoutTask(), application.getContext().getSystemSetting().getReassociateTimeout()*1000);
		beginReassociateTime = System.currentTimeMillis();
		wifiManager.reassociate();
	}
	
	 /**
	  * Wifi状态的接收器
	  */
	class WifiBroadcastReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			NetworkInfo networkInfo = (NetworkInfo) intent
					.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
			if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
				State state = networkInfo.getState();
				if (state == State.CONNECTED) {
					if (testStatus == EnumTestStatus.TESTING) {
						// 处理结果
						updateTestStatus(true);

						if(testStatus == EnumTestStatus.STOP) {
							return;
						}
						
						startReassociate();
					}
				} else if (state == State.DISCONNECTED) {
				} else if (state == State.UNKNOWN || state == State.SUSPENDED) {
					updateTestStatus(false);
					if(testStatus == EnumTestStatus.STOP) {
						return;
					}
					startReassociate();
				}

				// sendUpdateButtonStatus();
				Log.d(WifiBroadcastReceiver.class.getName(), "wifi's state = "
						+ state);
			}
		}

	}
	
	class TimeoutTask extends TimerTask {

		@Override
		public void run() {
			//关联超时
			updateTestStatus(false);

			if(testStatus == EnumTestStatus.STOP) {
				return;
			}
			
			startReassociate();
		}
	}

	class UpdateUIHandler extends Handler {

		public UpdateUIHandler(Looper looper) {
			super(looper);
		}

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);

			switch (msg.what) {
			case UPDATE_ASSOCIATE_TESTBEGIN: {
				Button btnBeignTest = (Button) findViewById(R.id.btnBeginTest);
				btnBeignTest.setVisibility(View.GONE);
				TextView txtView = (TextView) findViewById(R.id.txtOutput);
				txtView.append("开始关联测试" + "\n");
			}
				break;
			case UPDATE_ASSOCIATE_TESTOVER: {
				Button btnBeignTest = (Button) findViewById(R.id.btnBeginTest);
				btnBeignTest.setVisibility(View.VISIBLE);
				TextView txtView = (TextView) findViewById(R.id.txtOutput);
				txtView.append("关联测试" + "\n");
			}
				break;
			case UPDATE_ASSOCIATE_STATUS: {
				// 输出结果到命令行
				String str = (String) msg.obj;
				TextView txtView = (TextView) findViewById(R.id.txtOutput);
				txtView.append(str + "\n");
			}
				break;
			case UPDATE_ASSOCIATE_CHART: {
				ReassociateInfo info = (ReassociateInfo) msg.obj;
				dataset.getSeriesAt(0).add(info.getTestTimes(),
						info.getCurrentDelay() / 1000);
				
				//调整曲线图的坐标
				if(maxDelay < info.getCurrentDelay()) {
					maxDelay = info.getCurrentDelay();
					renderer.setYAxisMax(maxDelay/1000 + 5);
				}
				
				//刷新
				if (chartView != null) {
					chartView.invalidate();
				}
				
				txtCurrTestTimes.setText(info.getTestTimes() + "/"
						+ testTotalTimes);
				txtCurrDelay.setText(String.format("%.3fs",
						(float) (info.getCurrentDelay() / 1000.0)));
				txtAverageDelay.setText(String.format("%.3fs",
						(float) (info.getAverageDelay() / 1000.0)));

			}
				break;
			case UPDATE_ASSOCIATE_RESULT: {
				// 更新曲线图和当前测试结构
				LinearLayout layout = (LinearLayout) findViewById(R.id.testResultLayout);
				layout.setVisibility(View.VISIBLE);
				btnBeginTest.setText("开始测试");
				testStatus = EnumTestStatus.STOP;
				txtResultTimes.setText("关联请求次数 " + testTimes);
				txtResultSuccessTimes.setText("关联成功次数 " + associateSuccess);
				txtResultSuccessPercent
						.setText("关联成功百分比 "
								+ String.format(
										"%.2f %%",
										((float) associateSuccess / (float) testTimes) * 100));
				txtResultAverateDelay.setText("平均关联时延 " + averageDelay + "ms");
				try {
					if(wifiReceiver !=null){
						unregisterReceiver(wifiReceiver);
						wifiReceiver = null;
					}
				} catch (Exception e) {
					System.err.println("sv:"+ e);
				}
				
			}
				break;
			default:
				break;
			}
		}
	}
}

class ReassociateInfo {
	private long currentDelay = 0;
	private long averageDelay = 0;
	private int associateSuccess = 0;
	private int associateFailed = 0;
	private int testTimes = 0;

	public ReassociateInfo(long currentDelay, long averageDelay,
			int associateSuccess, int associateFailed) {
		this.currentDelay = currentDelay;
		this.averageDelay = averageDelay;
		this.associateFailed = associateFailed;
		this.associateSuccess = associateSuccess;
	}

	public int getTestTimes() {
		return testTimes;
	}

	public void setTestTimes(int testTimes) {
		this.testTimes = testTimes;
	}

	public long getCurrentDelay() {
		return currentDelay;
	}

	public void setCurrentDelay(int currentDelay) {
		this.currentDelay = currentDelay;
	}

	public long getAverageDelay() {
		return averageDelay;
	}

	public void setAverageDelay(int averageDelay) {
		this.averageDelay = averageDelay;
	}

	public int getAssociateSuccess() {
		return associateSuccess;
	}

	public void setAssociateSuccess(int associateSuccess) {
		this.associateSuccess = associateSuccess;
	}

	public int getAssociateFailed() {
		return associateFailed;
	}

	public void setAssociateFailed(int associateFailed) {
		this.associateFailed = associateFailed;
	}
}

enum EnumTestStatus {
	STOP, TESTING;
}


